import os
import hashlib
import random
from inspect import currentframe, getframeinfo

def add_row_xtransfer_popup ( popup_layout_output, text ):

    nrows = len(popup_layout_output[0]["rows"]) 

    popup_layout_output[0]["rows"].append({})
    popup_layout_output[0]["rows"][nrows]["permission"] = "read_write"
    popup_layout_output[0]["rows"][nrows]["id"] = "add_row_xtrasfer_popup_" + str(random.randint(0, 10000))
    popup_layout_output[0]["rows"][nrows]["type"] = "row"
    popup_layout_output[0]["rows"][nrows]["fields"] = []
    popup_layout_output[0]["rows"][nrows]["fields"].append({"type": "textbox", "display": text })
    popup_layout_output[0]["rows"][nrows]["fields"].append({"type": "void"})

    return popup_layout_output, nrows


def append_result_in_archive( popup_layout_output, pass_fail, display_name ):

    nrows = len(popup_layout_output[0]["rows"]) 

    popup_layout_output[0]["rows"].append({})
    popup_layout_output[0]["rows"][nrows]["permission"] = "read_write"
    popup_layout_output[0]["rows"][nrows]["id"] = "append_result_in_archive_" + str(random.randint(0, 10000))
    popup_layout_output[0]["rows"][nrows]["type"] = "row"
    popup_layout_output[0]["rows"][nrows]["fields"] = []
    popup_layout_output[0]["rows"][nrows]["fields"].append({"type": "textbox", "display": "info" })
    popup_layout_output[0]["rows"][nrows]["fields"].append({"type": "void"})

    if pass_fail == "pass" :
        popup_layout_output[0]["rows"][nrows]["fields"].append({"type": "archive", "selection": "pass", "items": []})
        popup_layout_output[0]["rows"][nrows]["fields"][2]["items"].append({"display": "pass", "data": "pass" })
    else :
        popup_layout_output[0]["rows"][nrows]["fields"].append({"type": "archive", "selection": "fail", "items": []})
        popup_layout_output[0]["rows"][nrows]["fields"][2]["items"].append({"display": "fail", "data": "fail" })

    popup_layout_output[0]["rows"][nrows]["fields"][2]["items"].append({"display": "command", "data": display_name })
    popup_layout_output[0]["rows"][nrows]["fields"][2]["items"].append({"display": "program", "data": os.path.basename(__file__).replace(".py","") })

    return popup_layout_output

def start_xtransfer_popup( rows_display, texbox_display ):

    popup_layout_output = []

    # Append a new dictionary to the list
    popup_layout_output.append({})

    # Populate the dictionary
    popup_layout_output[0]["type"] = "rows"
    popup_layout_output[0]["display"] = datetime.today().strftime('%Y.%m.%d') + " " + datetime.today().strftime('%H.%M.%S') + " " + str(random.randint(0, 10000))
    popup_layout_output[0]["id"] = rows_display.replace(" ","_") + "_" + str(random.randint(0, 10000))
    popup_layout_output[0]["expand"] = "on"

    # Initialize the "rows" key as a list and append a dictionary
    popup_layout_output[0]["rows"] = []

    popup_layout_output[0]["rows"].append({})
    popup_layout_output[0]["rows"][0]["permission"] = "read_write"
    popup_layout_output[0]["rows"][0]["id"] = rows_display.replace(" ","_") + "_" + str(random.randint(0, 10000))
    popup_layout_output[0]["rows"][0]["type"] = "row"
    popup_layout_output[0]["rows"][0]["fields"] = []
    popup_layout_output[0]["rows"][0]["fields"].append({"type": "textbox", "display": "timestamp" })
    popup_layout_output[0]["rows"][0]["fields"].append({"type": "void"})
    popup_layout_output[0]["rows"][0]["fields"].append({"type": "archive", "selection": "date", "items": []})
    popup_layout_output[0]["rows"][0]["fields"][2]["items"].append({"display": "date", "data": datetime.today().strftime('%Y-%m-%d') })
    popup_layout_output[0]["rows"][0]["fields"][2]["items"].append({"display": "time", "data": datetime.today().strftime('%H:%M:%S') })


    popup_layout_output[0]["rows"].append({})
    popup_layout_output[0]["rows"][1]["permission"] = "read_write"
    popup_layout_output[0]["rows"][1]["id"] = rows_display.replace(" ","_") + "_" + str(random.randint(0, 10000))
    popup_layout_output[0]["rows"][1]["type"] = "row"
    popup_layout_output[0]["rows"][1]["fields"] = []
    popup_layout_output[0]["rows"][1]["fields"].append({"type": "textbox", "display": texbox_display })
    popup_layout_output[0]["rows"][1]["fields"].append({"type": "void"})

    row_index = 1
    return popup_layout_output, row_index 


def get_files_and_checksums(folder_path):

    files_list = []
    checksums_list = []
    rand_list = []
    png_flac_list = []
    folder_path = os.path.expanduser( folder_path )

    at_least_one = 0
    for root, _, files in os.walk(folder_path):
        for filename in files:

            file_path = os.path.join(root, filename)
            error, png_flac = check_file_type(file_path)
            if error == 0 :
                at_least_one = 1
                with open(file_path, "rb") as f:
                    file_content = f.read()
                    full_hash = hashlib.sha256(file_content).hexdigest()

                files_list.append(file_path)
                checksums_list.append(full_hash)
                rand_list.append(str(random.randint(0, 10000)))
                png_flac_list.append(png_flac) 

    combined = list(zip(files_list, checksums_list, rand_list, png_flac_list))
    random.shuffle(combined)
    files_list, checksums_list, rand_list, png_flac_list = zip(*combined)
    
    files_list = list(files_list)
    checksums_list = list(checksums_list)
    rand_list = list(rand_list)
    png_flac_list = list(png_flac_list)

    error = 0
    if at_least_one == 0 :
        error = 1

    return error, files_list, checksums_list, rand_list, png_flac_list

def check_directory( directory_path, row_index, popup_obj ):

    error = 0
    text = ""
    rnd = str(random.randint(0, 10000))

    if not os.path.exists(directory_path):
        text = "Directory does not exist"
        error = 1
    
    if error == 0 :
        if not os.path.isdir(directory_path):
            text = "Path is not a directory"
            error = 1
    
    if len(popup_obj[0]["rows"][row_index]["fields"]) <= 2 :
        popup_obj[0]["rows"][row_index]["fields"].append({"type": "archive", "selection": os.path.basename(directory_path) + " read access " + rnd, "items":[]})

    popup_obj[0]["rows"][row_index]["fields"][2]["items"].append({"display": os.path.basename(directory_path) + " read access " + rnd, "data": text })

    return error, popup_obj

def check_at_least_one_file( directory_path, row_index, popup_obj ):

    error = 0
    text = ""
    rnd = str(random.randint(0, 10000))
    if not os.path.exists(directory_path):
        text = "Directory does not exist"
        error = 1
    
    if error == 0 :
        if not os.path.isdir(directory_path):
            text = "Path is not a directory"
            error = 1
    
    if error == 0 :
        error = 1
        items = os.listdir(directory_path)
        for item in items:
            if os.path.isfile(os.path.join(directory_path, item)):
                text = "Directory exists and contains at least one file"
                error = 0

        if error == 1 :
            text = "Directory exists and contains at least one file"

    if len(popup_obj[0]["rows"][row_index]["fields"]) <= 2 :
        popup_obj[0]["rows"][row_index]["fields"].append({"type": "archive", "selection": os.path.basename(directory_path) + " read access " + rnd, "items":[]})

    popup_obj[0]["rows"][row_index]["fields"][2]["items"].append({"display": os.path.basename(directory_path) + " read access " + rnd, "data": text })

    return error, popup_obj

def rename_final_popup_panel_name( panel_name, popup_obj, error ):

    display_name = panel_name

    if starts_with_inital_tag_number ( display_name ):
        display_name =  remove_initial_tag_number ( display_name )

    if error == 0 :
        popup_obj = append_result_in_archive( popup_obj, "pass", display_name )

    else :                                          
        popup_obj = append_result_in_archive( popup_obj, "fail", display_name )

    return popup_obj

def check_file_type(file_path):

    error, png_flac = is_png_or_flac(file_path)

    if error == 0 :
        try:
            with open(file_path, 'rb') as f:
                header = f.read(8)  # Read first 8 bytes
                if png_flac == "png" :
                    if header.startswith(b'\x89PNG'):
                        error = 0
                    else :
                        error = 1

                if png_flac == "flac" :
                    if header.startswith(b'fLaC'):
                        error = 0
                    else:
                        error = 1

        except FileNotFoundError:
            error = 1

        except Exception as e:
            error = 1

    return error, png_flac


def is_png_or_flac(file_path):

    extension = os.path.splitext(file_path)[1].lower()
    error = 1
    if extension == '.png':
        error = 0
    elif extension == '.flac':
        error = 0

    return error, extension[1:] 


def check_if_file_is_writable( file, row_index, popup_obj ):

    error = 0
    rnd = str(random.randint(0, 10000))

    file = os.path.expanduser(file)

    if file == "" :
        text = "no file specified"
        error = 1
        file = "void_" + rnd
    else :
        try:
            with open( file, 'w'):
                pass
            text = file + " is writable"
        except IOError:
            text = file + " is not writable"
            error = 1

    if len(popup_obj[0]["rows"][row_index]["fields"]) <= 2 :
        popup_obj[0]["rows"][row_index]["fields"].append({"type": "archive", "selection": os.path.basename(file) + " write access " + rnd, "items":[]})

    popup_obj[0]["rows"][row_index]["fields"][2]["items"].append({"display": os.path.basename(file) + " write access " + rnd, "data": text })
    return error, popup_obj


def check_if_file_is_readable( file, row_index, popup_obj ):

    error = 0
    file = os.path.expanduser(file)
    rnd = str(random.randint(0, 10000))

    if file == "" :
        text = "no file specified"
        error = 1
        file = "void_" + rnd
    else :
        try:
            with open( file, 'r'):
                pass
            text = file + " is readable"
        except IOError:
            text = file + " is not readable"
            error = 1

    if len(popup_obj[0]["rows"][row_index]["fields"]) <= 2 :
        popup_obj[0]["rows"][row_index]["fields"].append({"type": "archive", "selection": os.path.basename(file) + " read access " + rnd, "items":[]})

    popup_obj[0]["rows"][row_index]["fields"][2]["items"].append({"display": os.path.basename(file) + " read access " + rnd, "data": text })
    return error, popup_obj


def check_elaboration_archive( archive ):

    for obj in archive["resources"]:
        if obj["checksum"] == "" :
            print("check_elaboration_archive " + str(getframeinfo(currentframe()).lineno) )
            return 1

        if obj["source_path"] == "" :
            print("check_elaboration_archive " + str(getframeinfo(currentframe()).lineno) )
            return 1

        if ((obj["type"] != "png") and (obj["type"] != "flac")) :
            print("check_elaboration_archive " + str(getframeinfo(currentframe()).lineno) )
            return 1

        if obj["msbs_path"] == "" :
            print("check_elaboration_archive " + str(getframeinfo(currentframe()).lineno) )
            return 1

        if obj["lsbs_path"] == "" :
            print("check_elaboration_archive " + str(getframeinfo(currentframe()).lineno) )
            return 1

        if obj["metadata_path"] == "" :
            print("check_elaboration_archive " + str(getframeinfo(currentframe()).lineno) )
            return 1

        if obj["capacity"] == "" :
            print("check_elaboration_archive " + str(getframeinfo(currentframe()).lineno) )
            return 1


    for obj in archive["outputs"]:
        if obj["input_checksum"] == "" :
            print("check_elaboration_archive " + str(getframeinfo(currentframe()).lineno) )
            return 1

        if obj["perumted_lsbs_path"] == "" :
            print("check_elaboration_archive " + str(getframeinfo(currentframe()).lineno) )
            return 1

        if obj["length"] == "" :
            print("check_elaboration_archive " + str(getframeinfo(currentframe()).lineno) )
            return 1

        if obj["offset"] == "" :
            print("check_elaboration_archive " + str(getframeinfo(currentframe()).lineno) )
            return 1

        if obj["total_length"] == "" :
            print("check_elaboration_archive " + str(getframeinfo(currentframe()).lineno) )
            return 1

        if obj["output_path"] == "" :
            print("check_elaboration_archive " + str(getframeinfo(currentframe()).lineno) )
            return 1

    return 0


